﻿using HybridLab.Virtual;
using HybridLab.Workflow.Activities.Info;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Lab.Workflow.Activities;
using Microsoft.TeamFoundation.TestManagement.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HybridLab.Workflow.Activities.UI
{
	internal class HybridLabWizardData
	{
		// settings that the user will customize
		internal HybridLabWorkflowDetails HybridLabWorkflowDetails { get; private set; }

		internal EnvironmentDetailsEx EnvironmentDetails { get; private set; }
		internal BuildDetailsEx BuildDetails { get; private set; }
		internal DeploymentDetailsEx DeploymentDetails { get; private set; }
		internal RunTestDetailsEx TestDetails { get; private set; }

		// lists for the wizard
		internal TfsTeamProjectCollection Server { get; private set; }
		internal string TeamProject { get; private set; }
		internal List<ITestEnvironment> Environments { get; private set; }
		internal List<IBuildDefinition> availableBuildDefinitions;

		List<BuildDefinitionEx> buildDefinitions;
		internal List<BuildDefinitionEx> BuildDefinitions
		{
			get
			{
				if (((buildDefinitions == null) && (availableBuildDefinitions != null)) && (availableBuildDefinitions.Count > 0))
				{
					IEnumerable<IBuildDefinition> enumerable = availableBuildDefinitions.Where(def =>
					{
						try
						{
							return !WorkflowHelpers.GetProcessParameters(WorkflowHelpers.DeserializeWorkflow(def.Process.Parameters)).Values.Any<ProcessParameter>(obj => (typeof(LabWorkflowDetails) == obj.Type));
						}
						catch
						{
						}
						return false;
					});
					if (enumerable != null)
					{
						buildDefinitions = new List<BuildDefinitionEx>();
						foreach (IBuildDefinition definition in enumerable)
						{
							buildDefinitions.Add(new BuildDefinitionEx(definition));
						}
					}
				}
				return buildDefinitions;
			}
		}

		#region event handlers
		private EventHandler DataLoadCompletedHandler;
		private EventHandler DataLoadFailedHandler;

		internal event EventHandler DataLoadCompleted
		{
			add
			{
				EventHandler handler2;
				EventHandler dataLoadCompleted = this.DataLoadCompletedHandler;
				do
				{
					handler2 = dataLoadCompleted;
					EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
					dataLoadCompleted = Interlocked.CompareExchange<EventHandler>(ref this.DataLoadCompletedHandler, handler3, handler2);
				}
				while (dataLoadCompleted != handler2);
			}
			remove
			{
				EventHandler handler2;
				EventHandler dataLoadCompleted = this.DataLoadCompletedHandler;
				do
				{
					handler2 = dataLoadCompleted;
					EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
					dataLoadCompleted = Interlocked.CompareExchange<EventHandler>(ref this.DataLoadCompletedHandler, handler3, handler2);
				}
				while (dataLoadCompleted != handler2);
			}
		}

		internal event EventHandler DataLoadFailed
		{
			add
			{
				EventHandler handler2;
				EventHandler dataLoadFailed = this.DataLoadFailedHandler;
				do
				{
					handler2 = dataLoadFailed;
					EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
					dataLoadFailed = Interlocked.CompareExchange<EventHandler>(ref this.DataLoadFailedHandler, handler3, handler2);
				}
				while (dataLoadFailed != handler2);
			}
			remove
			{
				EventHandler handler2;
				EventHandler dataLoadFailed = this.DataLoadFailedHandler;
				do
				{
					handler2 = dataLoadFailed;
					EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
					dataLoadFailed = Interlocked.CompareExchange<EventHandler>(ref this.DataLoadFailedHandler, handler3, handler2);
				}
				while (dataLoadFailed != handler2);
			}
		}
		#endregion

		private HybridLabWizardData()
		{
			EnvironmentDetails = new EnvironmentDetailsEx();
			BuildDetails = new BuildDetailsEx();
			DeploymentDetails = new DeploymentDetailsEx(this);
		}

		public HybridLabWizardData(TfsTeamProjectCollection server, string teamProject, HybridLabWorkflowDetails hybridLabWorkflowDetails)
			: this()
		{
			if (server == null)
			{
				throw new ArgumentNullException("server");
			}
			if (string.IsNullOrEmpty(teamProject))
			{
				throw new ArgumentNullException("teamProject");
			}
			Server = server;
			TeamProject = teamProject;
			HybridLabWorkflowDetails = hybridLabWorkflowDetails;
			if (HybridLabWorkflowDetails == null)
			{
				HybridLabWorkflowDetails = new HybridLabWorkflowDetails();
			}
			TestDetails = new RunTestDetailsEx(Server, TeamProject, HybridLabWorkflowDetails.TestParameters);
		}

		internal HybridLabWorkflowDetails GetWorkflowDetails()
		{
			var workflowDetails = new HybridLabWorkflowDetails();
			SaveEnvironmentDetails(workflowDetails);
			SaveBuildDetails(workflowDetails);
			SaveDeploymentDetails(workflowDetails);
			workflowDetails.TestParameters = TestDetails.GetDetails();
			return workflowDetails;
		}

		private void SaveBuildDetails(HybridLabWorkflowDetails workflowDetails)
		{
			workflowDetails.BuildDetails.IsTeamSystemBuild = BuildDetails.IsTeamSystemBuild;
			workflowDetails.BuildDetails.QueueNewBuild = BuildDetails.QueueNewBuild;
			workflowDetails.BuildDetails.CustomBuildPath = BuildDetails.CustomBuildPath;
			workflowDetails.BuildDetails.BuildDefinitionUri = (BuildDetails.BuildDefinition != null) ? BuildDetails.BuildDefinition.Definition.Uri : null;
			workflowDetails.BuildDetails.BuildDefinitionName = (BuildDetails.BuildDefinition != null) ? BuildDetails.BuildDefinition.Definition.Name : null;
			workflowDetails.BuildDetails.BuildUri = ((BuildDetails.BuildDetail == null) || BuildDetails.BuildDetail.IsLatestOption) ? null : BuildDetails.BuildDetail.Build.Uri;
			workflowDetails.BuildDetails.Configuration = BuildDetails.Configuration;
		}

		private void SaveDeploymentDetails(HybridLabWorkflowDetails workflowDetails)
		{
			workflowDetails.DeploymentDetails.DeploymentNeeded = DeploymentDetails.DeploymentNeeded;
			workflowDetails.DeploymentDetails.UseRoleForDeployment = false;
			workflowDetails.DeploymentDetails.Scripts = DeploymentScriptUtils.ToStringList(this.DeploymentDetails.Scripts);
			workflowDetails.DeploymentDetails.TakePostDeploymentSnapshot = DeploymentDetails.TakePostDeploymentSnapshot;
			workflowDetails.DeploymentDetails.PostDeploymentSnapshotName = DeploymentDetails.PostDeploymentSnapshotPrefix;
		}

		private void SaveEnvironmentDetails(HybridLabWorkflowDetails workflowDetails)
		{
			var lab = EnvironmentDetails.Environment.GetLab(Server);
			var labDetails = new LabEnvironmentDetails();
			if (lab != null)
			{
				labDetails.Disposition = lab.Disposition;
				labDetails.LabEnvironmentName = lab.FullName;
				labDetails.LabEnvironmentUri = lab.Uri;
			}
			workflowDetails.HybridLab = new HybridLabEnvironment()
			{
				RevertToSnapshot = EnvironmentDetails.RevertToSnapshot,
				Credentials = EnvironmentDetails.Credentials,
				EnvironmentSnapshotInfo = EnvironmentDetails.SnapshotInfo,
				HostName = EnvironmentDetails.HostName,
				HostType = EnvironmentDetails.HostType,
				LabEnvironment = labDetails,
				InteractiveUserPassword = EnvironmentDetails.InteractiveUserPassword
			};
		}

		internal void Initialize()
		{
			LoadData();
		}

		private async void LoadData()
		{
			try
			{
				await Task.Run(() =>
					{
						var service = Server.GetService<ITestManagementService>();
						Environments = new List<ITestEnvironment>();
						foreach (ITestController c in service.TestControllers.Query())
						{
							Environments.AddRange(c.TestEnvironments.Query().Where(en => en.EnvironmentType == "Physical").ToList());
						}
						var server = Server.GetService<IBuildServer>();
						availableBuildDefinitions = server.QueryBuildDefinitions(TeamProject).ToList<IBuildDefinition>();
						TestDetails.LoadTestPlans();
					});
			}
			catch (AggregateException ex)
			{
				RaiseLoadFailureEvent(ex.InnerException);
			}
			InitializeData();
			RaiseEvent(this.DataLoadCompletedHandler);
		}

		private void InitializeData()
		{
			try
			{
				if (HybridLabWorkflowDetails != null)
				{
					InitializeEnvironmentDetails();
					InitializeBuildDetails();
					InitializeDeploymentDetails();
					TestDetails.InitializeData();
				}
			}
			catch (Exception ex)
			{
				RaiseLoadFailureEvent(ex);
			}
		}

		private void InitializeDeploymentDetails()
		{
			DeploymentDetails.DeploymentNeeded = HybridLabWorkflowDetails.DeploymentDetails.DeploymentNeeded;
			DeploymentDetails.TakePostDeploymentSnapshot = HybridLabWorkflowDetails.DeploymentDetails.TakePostDeploymentSnapshot;
			DeploymentDetails.PostDeploymentSnapshotPrefix = HybridLabWorkflowDetails.DeploymentDetails.PostDeploymentSnapshotName;
			DeploymentDetails.Scripts = DeploymentScriptUtils.ToDeploymentScript(HybridLabWorkflowDetails.DeploymentDetails.Scripts);
		}

		private void InitializeBuildDetails()
		{
			BuildDetails.IsTeamSystemBuild = HybridLabWorkflowDetails.BuildDetails.IsTeamSystemBuild;
			BuildDetails.QueueNewBuild = HybridLabWorkflowDetails.BuildDetails.QueueNewBuild;
			BuildDetails.CustomBuildPath = HybridLabWorkflowDetails.BuildDetails.CustomBuildPath;
			if (BuildDefinitions != null)
			{
				BuildDetails.BuildDefinition = BuildDefinitions.FirstOrDefault(def => def.Definition.Uri == HybridLabWorkflowDetails.BuildDetails.BuildDefinitionUri);
			}
			if (BuildDetails.BuildList != null)
			{
				if (HybridLabWorkflowDetails.BuildDetails.BuildUri == null)
				{
					BuildDetails.BuildDetail = BuildDetails.BuildList.FirstOrDefault(b => b.IsLatestOption);
				}
				else
				{
					BuildDetails.BuildDetail = BuildDetails.BuildList.FirstOrDefault(build => !build.IsLatestOption && build.Build.Uri == HybridLabWorkflowDetails.BuildDetails.BuildUri);
					if (BuildDetails.BuildDetail == null)
					{
						BuildDetails.BuildDetail = BuildDetails.BuildList.FirstOrDefault(b => b.IsLatestOption);
					}
				}
			}
			BuildDetails.Configuration = (HybridLabWorkflowDetails.BuildDetails.Configuration == null || BuildDetails.ConfigurationList == null) ? null :
				BuildDetails.ConfigurationList.FirstOrDefault(con => BuildDetailsEx.PlatformConfigurationEquals(con, HybridLabWorkflowDetails.BuildDetails.Configuration));
		}

		private void InitializeEnvironmentDetails()
		{
			if (HybridLabWorkflowDetails.HybridLab != null && HybridLabWorkflowDetails.HybridLab.LabEnvironment != null)
			{
				EnvironmentDetails.Environment = Environments.FirstOrDefault(le => le.LabEnvironmentUri == HybridLabWorkflowDetails.HybridLab.LabEnvironment.LabEnvironmentUri);
				EnvironmentDetails.Credentials = HybridLabWorkflowDetails.HybridLab.Credentials;
				EnvironmentDetails.HostName = HybridLabWorkflowDetails.HybridLab.HostName;
				EnvironmentDetails.HostType = HybridLabWorkflowDetails.HybridLab.HostType;
				EnvironmentDetails.SnapshotInfo = HybridLabWorkflowDetails.HybridLab.EnvironmentSnapshotInfo;
				EnvironmentDetails.RevertToSnapshot = HybridLabWorkflowDetails.HybridLab.RevertToSnapshot;
				EnvironmentDetails.InteractiveUserPassword = HybridLabWorkflowDetails.HybridLab.InteractiveUserPassword;
			}
		}

		private void RaiseEvent(EventHandler eventToRaise)
		{
			if (eventToRaise != null)
			{
				eventToRaise(this, null);
			}
		}

		protected void RaiseLoadFailureEvent(Exception reason)
		{
			if (DataLoadFailedHandler != null)
			{
				DataLoadFailedEventArgs e = new DataLoadFailedEventArgs(reason);
				DataLoadFailedHandler(this, e);
			}
		}
	}
}
